package com.cwnu.sw.cys.core.user.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.cwnu.sw.cys.core.common.annotation.RedisLock;
import com.cwnu.sw.cys.core.common.domain.vo.resp.UserInfoResp;
import com.cwnu.sw.cys.core.common.event.UserBlackEvent;
import com.cwnu.sw.cys.core.common.event.UserRegisterEvent;
import com.cwnu.sw.cys.core.common.utils.AssertUtil;
import com.cwnu.sw.cys.core.user.dao.BlackDao;
import com.cwnu.sw.cys.core.user.dao.ItemConfigDao;
import com.cwnu.sw.cys.core.user.dao.UserBackpackDao;
import com.cwnu.sw.cys.core.user.dao.UserDao;
import com.cwnu.sw.cys.core.user.domain.entity.*;
import com.cwnu.sw.cys.core.user.domain.enums.BlackTypeEnum;
import com.cwnu.sw.cys.core.user.domain.enums.ItemEnum;
import com.cwnu.sw.cys.core.user.domain.enums.ItemTypeEnum;
import com.cwnu.sw.cys.core.user.domain.vo.req.BlackReq;
import com.cwnu.sw.cys.core.user.domain.vo.resp.BadgeResp;
import com.cwnu.sw.cys.core.user.service.UserService;
import com.cwnu.sw.cys.core.user.service.adapter.UserAdapter;
import com.cwnu.sw.cys.core.user.service.cache.ItemCache;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.event.TransactionalEventListener;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author jisam
 * @version 1.0
 * @contact "jisamchan@outlook.com"
 * @date 13/02/2025
 * @description
 */
@Service
@Slf4j
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;

    @Autowired
    private UserBackpackDao userBackpackDao;

    @Autowired
    private ItemCache itemCache;

    @Autowired
    private ItemConfigDao itemConfigDao;

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    @Autowired
    private BlackDao blackDao;
    @Override
    @Transactional
    public Long register(User insertUser) {
        boolean save = userDao.save(insertUser);
        // TODO 用户注册事件
        applicationEventPublisher.publishEvent(new UserRegisterEvent(this,insertUser));

        return save ? insertUser.getId() : null;
    }

    @Override
    public UserInfoResp getUserInfo(Long uid) {
        User userById =  userDao.getById(uid);
        Integer countByValue = userBackpackDao.getCountByValue(uid, ItemEnum.MODIFY_NAME_CARD.getId());
        return UserAdapter.builderUserInfoResp(userById, countByValue);
    }

    /**
     * @param uid
     * @param newName
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @RedisLock(key = "#uid")
    public Void modifyName(Long uid, String newName) {
        User oldUser = userDao.getByName(newName);
        AssertUtil.isEmpty(oldUser, "用户名已存在");
//        User userById =  userDao.getById(uid);
//        Integer countByValue = userBackpackDao.getCountByValue(uid, ItemEnum.MODIFY_NAME_CARD.getId());
        UserBackpack firstModifyCard = userBackpackDao.getFirstValidItem(uid, ItemEnum.MODIFY_NAME_CARD.getId());
        AssertUtil.isNotEmpty(firstModifyCard, "改名卡不足");
        // DONE 修改用户名事件
        // 消耗改名卡
        boolean success = userBackpackDao.useItem(firstModifyCard);
        if(success)
        {
            userDao.modifyName(uid, newName);
            // TODO 删除缓存
        }

        return null;
    }

    /**
     * @param uid
     * @return
     */
    @Override
    public List<BadgeResp> getBadges(Long uid) {
        // 查询所有的徽章
        List<ItemConfig> itemConfigs = itemCache.getByType(ItemTypeEnum.BADGE.getType());
        List<Long> badges = itemConfigs.stream().map(ItemConfig::getId).collect(Collectors.toList());
        // 查询用户所有的徽章
        List<UserBackpack> backpacks = userBackpackDao.getByItemId(uid,badges);
        User user = userDao.getById(uid);
        return UserAdapter.builderBadgeResp(itemConfigs, backpacks, user);
    }

    @Override
    public void wearingBadges(Long uid, Long itemId) {
        UserBackpack firstValidItem = userBackpackDao.getFirstValidItem(uid, itemId);
        AssertUtil.isNotEmpty(firstValidItem, "未拥有该徽章");
        ItemConfig itemConfig = itemConfigDao.getById(firstValidItem.getItemId());
        AssertUtil.equal(itemConfig.getType(), ItemTypeEnum.BADGE.getType(), "徽章才可以佩戴");
        boolean success = userDao.waringBadges(uid, itemId);
        if(success)
        {
            // TODO 删除缓存
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void black(BlackReq req) {
        Long uid = req.getUid();
        Black user = new Black();
        user.setTarget(uid.toString());
        user.setType(BlackTypeEnum.UID.getType());
        blackDao.save(user);
        User byId = userDao.getById(uid);
        AssertUtil.isNotEmpty(byId, "用户不存在");
        blackIp(Optional.ofNullable(byId.getIpInfo()).map(IpInfo::getCreateIp).orElse(null));
        blackIp(Optional.ofNullable(byId.getIpInfo()).map(IpInfo::getUpdateIp).orElse(null));
        applicationEventPublisher.publishEvent(new UserBlackEvent(this, byId));
    }

    private void blackIp(String ip) {
        if (StrUtil.isBlank(ip)) {
            return;
        }
        try {
            Black user = new Black();
            user.setTarget(ip);
            user.setType(BlackTypeEnum.IP.getType());
            blackDao.save(user);
        } catch (Exception e) {
            log.error("duplicate black ip:{}", ip);
        }
    }

    @Override
    public boolean saveBatch(Collection<User> entityList, int batchSize) {
        return false;
    }

    @Override
    public boolean saveOrUpdateBatch(Collection<User> entityList, int batchSize) {
        return false;
    }

    @Override
    public boolean updateBatchById(Collection<User> entityList, int batchSize) {
        return false;
    }

    @Override
    public boolean saveOrUpdate(User entity) {
        return false;
    }

    @Override
    public User getOne(Wrapper<User> queryWrapper, boolean throwEx) {
        return null;
    }

    @Override
    public Map<String, Object> getMap(Wrapper<User> queryWrapper) {
        return null;
    }

    @Override
    public <V> V getObj(Wrapper<User> queryWrapper, Function<? super Object, V> mapper) {
        return null;
    }

    @Override
    public BaseMapper<User> getBaseMapper() {
        return null;
    }
}
